package main

import (
	"bufio"
	"config-client-v1/test/tcp-server-demo/pkg"
	"flag"
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net"
	"strings"
	"sync"
	"time"
)

const BYTE_LENGTH = 8192 // 单次循环最大读取的字节数量, 如果单次发送的数据包大于这里, 则需要多次读取

var userNum int

type Client struct {
	RemoteAddr   string        `json:"remote_addr"` // 客户端 IP + 端口
	Connection   net.Conn      `json:"-"`
	Reader       *bufio.Reader `json:"-"`
	CreateTime   time.Time     `json:"create_time"`    // 连接时间
	LastDataTime time.Time     `json:"last_data_time"` // 最近一次接收数据的时间
}

type OnlineMapStu struct {
	M          map[string]*Client
	Register   chan *Client
	Unregister chan *Client
	sync.RWMutex
}

var OnlineMap OnlineMapStu
var serverPort string
var httpPort string
var list []*pkg.FrameItemParam

func main() {
	port := flag.String("port", "8088", "监听tcp端口")
	httpPortPointer := flag.String("http_port", "7088", "监听http端口")
	flag.Parse()
	serverPort = *port
	httpPort = *httpPortPointer

	OnlineMap = OnlineMapStu{}
	OnlineMap.M = make(map[string]*Client)
	OnlineMap.Register = make(chan *Client, 1000)
	OnlineMap.Unregister = make(chan *Client, 1000)

	//go testSend()
	go connManage()
	go httpRun()

	listener, err := net.Listen("tcp", ":"+serverPort)
	if err != nil {
		log.Fatal("tcp 服务启动失败 " + err.Error())
	}
	fmt.Printf("%-32s%-32s\n", "tcp listen on "+serverPort, "OK")

	for {
		conn, err2 := listener.Accept()
		if err2 != nil {
			fmt.Println("listener Accept Error", err2)
			break
		}
		remoteAddr := conn.RemoteAddr().String()
		reader := bufio.NewReader(conn)
		client := &Client{
			RemoteAddr:   remoteAddr,
			Connection:   conn,
			Reader:       reader,
			CreateTime:   time.Now(),
			LastDataTime: time.Now(),
		}
		OnlineMap.Register <- client
		userNum++
		//_ = conn.SetReadDeadline(time.Now().Add(10 * time.Second))
		go handleCon(client)
	}
}

func handleCon(client *Client) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("handleCon Error: ", err)
		}
		OnlineMap.Unregister <- client
	}()
	remoteAddr := client.Connection.RemoteAddr().String() // 客户端IP:PORT
	var buffer [BYTE_LENGTH]byte
	for {
		n, err := client.Connection.Read(buffer[0:])
		if err != nil {
			if err == net.ErrClosed || strings.Contains(err.Error(), "use of closed network connection") || strings.Contains(err.Error(), "read: connection reset by peer") || strings.Contains(err.Error(), "forcibly closed") {
				fmt.Printf("[%s ~ %s]# 连接已关闭或重置\n", pkg.GetNow(), remoteAddr)
			} else {
				fmt.Println("unknown read error: ", err.Error())
			}
			return
		}
		OnlineMap.Register <- client

		str := pkg.ByteArrayToHexStr(buffer[0:n])
		_ = pkg.WriteStringToLog(fmt.Sprintf("[%s ~ %s]# %s", pkg.GetNow(), remoteAddr, str), "raw_data.log", "")
		/* --- 处理 rawData 开始 --- */
		//now := pkg.GetNow()

		fmt.Println("--------------------------------")
		fmt.Printf("【recv】%s ~ %s# len=%d : %s\n", pkg.GetNow(), remoteAddr, n, str)
		/* --- 处理 rawData 结束 --- */
		clearBuffer(&buffer, n)

	}
}

// 连接管理, 检查连接是否在线, 删除离线的client
func connManage() {
	// 连接和断开管理
	go func() {
		for {
			select {
			case client := <-OnlineMap.Register:
				OnlineMap.RLock()
				_, ok := OnlineMap.M[client.RemoteAddr]
				if !ok {
					fmt.Printf("[%s ~ %s]# 新客户端已连接 %s\n", pkg.GetNow(), client.RemoteAddr, "WELL")
				}
				OnlineMap.RUnlock()
				client.LastDataTime = time.Now()
				OnlineMap.Lock()
				OnlineMap.M[client.RemoteAddr] = client
				OnlineMap.Unlock()
			case client := <-OnlineMap.Unregister:
				fmt.Printf("用户掉线 %s\n", client.RemoteAddr)
				_ = client.Connection.Close()
				OnlineMap.Lock()
				delete(OnlineMap.M, client.RemoteAddr)
				OnlineMap.Unlock()
			}
		}
	}()

	// 超过一定时间未发送数据, 自动算离线; 1秒一次循环判断, 删除最后一次发送数据的时间大于5秒的client
	//go func() {
	//	for {
	//		time.Sleep(1 * time.Second)
	//		now := time.Now()
	//		OnlineMap.RLock()
	//		for _, client := range OnlineMap.M {
	//			if now.Sub(client.LastDataTime) > time.Duration(timeoutKick)*time.Second {
	//				fmt.Println("客户端长时间未发送数据, 已掉线: ", client.RemoteAddr)
	//				OnlineMap.Unregister <- client
	//			}
	//		}
	//		OnlineMap.RUnlock()
	//	}
	//}()
}

func clearBuffer(buf *[BYTE_LENGTH]byte, n int) {
	if n >= BYTE_LENGTH {
		n = BYTE_LENGTH
	}
	for i := 0; i < n; i++ {
		buf[i] = 0
	}
}

func httpRun() {
	var r *gin.Engine
	gin.SetMode(gin.ReleaseMode)
	// 设置全局日志中间件
	r = gin.New()

	r.GET("/client_info", func(ctx *gin.Context) {
		OnlineMap.RLock()
		defer OnlineMap.RUnlock()
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "success",
			"data":    OnlineMap.M,
		})
	})
	fmt.Printf("%-32s%-32s\n", "http listen on "+httpPort, "OK")
	err := r.Run(":" + httpPort) // 监听http server
	if err != nil {
		log.Fatal(err.Error())
	}
}

func testSend() {
	for {
		data := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}
		str := pkg.ByteArrayToHexStr(data)
		OnlineMap.RLock()
		for _, client := range OnlineMap.M {
			n, err := client.Connection.Write(data)
			if err != nil {
				fmt.Printf("tcp写入失败 %s\n", err.Error())
				continue
			}
			fmt.Printf("【send】%s ~ %s# len=%d : %s\n", pkg.GetNow(), client.RemoteAddr, n, str)
		}
		OnlineMap.RUnlock()
		time.Sleep(time.Second * 1)
	}
}
